home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / netinet / udp_usrreq.c < prev    next >
C/C++ Source or Header  |  1993-08-12  |  14KB  |  586 lines

  1. RCS_ID_C="$Id: udp_usrreq.c,v 1.9 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: udp_usrreq.c,v $
  9.  * Revision 1.9  1993/06/04  11:16:15  jraja
  10.  * Fixes for first public release.
  11.  *
  12.  * Revision 1.8  1993/05/17  00:16:44  ppessi
  13.  * Changed RCS version. Added rcsid.
  14.  *
  15.  * Revision 1.7  1993/04/11  22:26:55  jraja
  16.  * Added STKARGFUN to protocol input & output functions (if used in protosw).
  17.  *
  18.  * Revision 1.6  93/04/05  19:06:49  19:06:49  jraja (Jarno Tapio Rajahalme)
  19.  * Changed storage of the spl functions  return values to type spl_t.
  20.  * Added include for conf.h to every .c file.
  21.  * 
  22.  * Revision 1.5  93/03/22  16:59:42  16:59:42  jraja (Jarno Tapio Rajahalme)
  23.  * Changed bcopy()s and bzero()s with word aligned pointers to
  24.  * aligned_b(copy|zero) ar aligned_b(copy|zero)_const. The latter is for calls
  25.  * in which the size is constant.
  26.  * These can be disabled by defining NOALIGN.
  27.  *  Converted bcopys doing structure copies (on aligned pointers) to structure
  28.  * assignments, since at least SASC produces better code with assignment.
  29.  * 
  30.  * Revision 1.4  93/03/16  08:29:26  08:29:26  jraja (Jarno Tapio Rajahalme)
  31.  * Made PRU_SENSE (stat) unsupported on AmiTCP
  32.  * 
  33.  * Revision 1.3  93/03/03  20:56:38  20:56:38  jraja (Jarno Tapio Rajahalme)
  34.  * Moved some data definitions from netinet/udp_var.h to here.
  35.  * 
  36.  * Revision 1.2  93/02/26  10:01:59  10:01:59  jraja (Jarno Tapio Rajahalme)
  37.  * Made this compile with ANSI C (added prototypes).
  38.  * Added dest argument to icmp_error call (which doesn't use it in this case).
  39.  * 
  40.  * Revision 1.1  92/11/17  16:31:33  16:31:33  jraja (Jarno Tapio Rajahalme)
  41.  * Initial revision
  42.  * 
  43.  */
  44.  
  45. /*
  46.  * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
  47.  * All rights reserved.
  48.  *
  49.  * Redistribution and use in source and binary forms, with or without
  50.  * modification, are permitted provided that the following conditions
  51.  * are met:
  52.  * 1. Redistributions of source code must retain the above copyright
  53.  *    notice, this list of conditions and the following disclaimer.
  54.  * 2. Redistributions in binary form must reproduce the above copyright
  55.  *    notice, this list of conditions and the following disclaimer in the
  56.  *    documentation and/or other materials provided with the distribution.
  57.  * 3. All advertising materials mentioning features or use of this software
  58.  *    must display the following acknowledgement:
  59.  *    This product includes software developed by the University of
  60.  *    California, Berkeley and its contributors.
  61.  * 4. Neither the name of the University nor the names of its contributors
  62.  *    may be used to endorse or promote products derived from this software
  63.  *    without specific prior written permission.
  64.  *
  65.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  66.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  67.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  68.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  69.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  70.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  71.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  72.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  73.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  74.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  75.  * SUCH DAMAGE.
  76.  *
  77.  *    @(#)udp_usrreq.c    7.20 (Berkeley) 4/20/91
  78.  */
  79.  
  80. #include <conf.h>
  81.  
  82. #include <sys/param.h>
  83. #include <sys/systm.h>
  84. #include <sys/malloc.h>
  85. #include <sys/mbuf.h>
  86. #include <sys/protosw.h>
  87. #include <sys/socket.h>
  88. #include <sys/socketvar.h>
  89. #include <sys/synch.h>
  90.  
  91. #include <net/if.h>
  92. #include <net/route.h>
  93.  
  94. #include <netinet/in.h>
  95. #include <netinet/in_systm.h>
  96. #include <netinet/ip.h>
  97. #include <netinet/in_pcb.h>
  98. #include <netinet/ip_var.h>
  99. #include <netinet/ip_icmp.h>
  100. #include <netinet/udp.h>
  101. #include <netinet/udp_var.h>
  102.  
  103. #include <netinet/udp_usrreq_protos.h>
  104. #include <netinet/ip_input_protos.h>
  105. #include <netinet/ip_output_protos.h>
  106. #include <netinet/ip_icmp_protos.h>
  107. #include <netinet/in_cksum_protos.h>
  108. #include <netinet/in_pcb_protos.h>
  109. #include <netinet/in_protos.h>
  110. #include <kern/uipc_socket2_protos.h>
  111.  
  112. /* --- start moved from udp_var.h */
  113. struct    inpcb udb = { 0 };
  114. struct    udpstat udpstat = { 0 };
  115. /* --- end moved from udp_var.h */
  116.  
  117. struct    inpcb *udp_last_inpcb = &udb;
  118.  
  119. /*
  120.  * UDP protocol implementation.
  121.  * Per RFC 768, August, 1980.
  122.  */
  123. void
  124. udp_init()
  125. {
  126.  
  127.     udb.inp_next = udb.inp_prev = &udb;
  128. }
  129.  
  130. #if    !COMPAT_42
  131. int    udpcksum = 1;
  132. #else
  133. int    udpcksum = 0;        /* XXX */
  134. #endif
  135. int    udp_ttl = UDP_TTL;
  136.  
  137. struct    sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
  138.  
  139. void STKARGFUN
  140. udp_input(m, iphlen)
  141.     register struct mbuf *m;
  142.     int iphlen;
  143. {
  144.     register struct ip *ip;
  145.     register struct udphdr *uh;
  146.     register struct inpcb *inp;
  147.     struct mbuf *opts = 0;
  148.     int len;
  149.     struct ip save_ip;
  150.     struct in_addr dest; /* not REALLY used */
  151.  
  152.     udpstat.udps_ipackets++;
  153.  
  154.     /*
  155.      * Strip IP options, if any; should skip this,
  156.      * make available to user, and use on returned packets,
  157.      * but we don't yet have a way to check the checksum
  158.      * with options still present.
  159.      */
  160.     if (iphlen > sizeof (struct ip)) {
  161.         ip_stripoptions(m, (struct mbuf *)0);
  162.         iphlen = sizeof(struct ip);
  163.     }
  164.  
  165.     /*
  166.      * Get IP and UDP header together in first mbuf.
  167.      */
  168.     ip = mtod(m, struct ip *);
  169.     if (m->m_len < iphlen + sizeof(struct udphdr)) {
  170.         if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
  171.             udpstat.udps_hdrops++;
  172.             return;
  173.         }
  174.         ip = mtod(m, struct ip *);
  175.     }
  176.     uh = (struct udphdr *)((caddr_t)ip + iphlen);
  177.  
  178.     /*
  179.      * Make mbuf data length reflect UDP length.
  180.      * If not enough data to reflect UDP length, drop.
  181.      */
  182.     len = ntohs((u_short)uh->uh_ulen);
  183.     if (ip->ip_len != len) {
  184.         if (len > ip->ip_len) {
  185.             udpstat.udps_badlen++;
  186.             goto bad;
  187.         }
  188.         m_adj(m, len - ip->ip_len);
  189.         /* ip->ip_len = len; */
  190.     }
  191.     /*
  192.      * Save a copy of the IP header in case we want restore it
  193.      * for sending an ICMP error message in response.
  194.      */
  195.     save_ip = *ip;
  196.  
  197.     /*
  198.      * Checksum extended UDP header and data.
  199.      */
  200.     if (udpcksum && uh->uh_sum) {
  201.         ((struct ipovly *)ip)->ih_next = 0;
  202.         ((struct ipovly *)ip)->ih_prev = 0;
  203.         ((struct ipovly *)ip)->ih_x1 = 0;
  204.         ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
  205.         if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
  206.             udpstat.udps_badsum++;
  207.             m_freem(m);
  208.             return;
  209.         }
  210.     }
  211.  
  212.     /*
  213.      * Locate pcb for datagram.
  214.      */
  215.     inp = udp_last_inpcb;
  216.     if (inp->inp_lport != uh->uh_dport ||
  217.         inp->inp_fport != uh->uh_sport ||
  218.         inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
  219.         inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
  220.         inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
  221.             ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
  222.         if (inp)
  223.             udp_last_inpcb = inp;
  224.         udpstat.udpps_pcbcachemiss++;
  225.     }
  226.     if (inp == 0) {
  227.         /* don't send ICMP response for broadcast packet */
  228.         udpstat.udps_noport++;
  229.         if (m->m_flags & M_BCAST) {
  230.             udpstat.udps_noportbcast++;
  231.             goto bad;
  232.         }
  233.         *ip = save_ip;
  234.         ip->ip_len += iphlen;
  235.         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, dest);
  236.         return;
  237.     }
  238.  
  239.     /*
  240.      * Construct sockaddr format source address.
  241.      * Stuff source address and datagram in user buffer.
  242.      */
  243.     udp_in.sin_port = uh->uh_sport;
  244.     udp_in.sin_addr = ip->ip_src;
  245.     if (inp->inp_flags & INP_CONTROLOPTS) {
  246.         struct mbuf **mp = &opts;
  247.         struct mbuf *udp_saveopt();
  248.  
  249.         if (inp->inp_flags & INP_RECVDSTADDR) {
  250.             *mp = udp_saveopt((caddr_t) &ip->ip_dst,
  251.                 sizeof(struct in_addr), IP_RECVDSTADDR);
  252.             if (*mp)
  253.                 mp = &(*mp)->m_next;
  254.         }
  255. #ifdef notyet
  256.         /* options were tossed above */
  257.         if (inp->inp_flags & INP_RECVOPTS) {
  258.             *mp = udp_saveopt((caddr_t) opts_deleted_above,
  259.                 sizeof(struct in_addr), IP_RECVOPTS);
  260.             if (*mp)
  261.                 mp = &(*mp)->m_next;
  262.         }
  263.         /* ip_srcroute doesn't do what we want here, need to fix */
  264.         if (inp->inp_flags & INP_RECVRETOPTS) {
  265.             *mp = udp_saveopt((caddr_t) ip_srcroute(),
  266.                 sizeof(struct in_addr), IP_RECVRETOPTS);
  267.             if (*mp)
  268.                 mp = &(*mp)->m_next;
  269.         }
  270. #endif
  271.     }
  272.     iphlen += sizeof(struct udphdr);
  273.     m->m_len -= iphlen;
  274.     m->m_pkthdr.len -= iphlen;
  275.     m->m_data += iphlen;
  276.     if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
  277.         m, opts) == 0) {
  278.         udpstat.udps_fullsock++;
  279.         goto bad;
  280.     }
  281.     sorwakeup(inp->inp_socket);
  282.     return;
  283. bad:
  284.     m_freem(m);
  285.     if (opts)
  286.         m_freem(opts);
  287. }
  288.  
  289. /*
  290.  * Create a "control" mbuf containing the specified data
  291.  * with the specified type for presentation with a datagram.
  292.  */
  293. struct mbuf *
  294. udp_saveopt(p, size, type)
  295.     caddr_t p;        /* aligned */
  296.     register int size;
  297.     int type;
  298. {
  299.     register struct cmsghdr *cp;
  300.     struct mbuf *m;
  301.  
  302.     if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
  303.         return ((struct mbuf *) NULL);
  304.     cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
  305.     aligned_bcopy(p, (caddr_t)(cp + 1), size);
  306.     size += sizeof(*cp);
  307.     m->m_len = size;
  308.     cp->cmsg_len = size;
  309.     cp->cmsg_level = IPPROTO_IP;
  310.     cp->cmsg_type = type;
  311.     return (m);
  312. }
  313.  
  314. /*
  315.  * Notify a udp user of an asynchronous error;
  316.  * just wake up so that he can collect error status.
  317.  */
  318. void
  319. udp_notify(inp, errno)
  320.     register struct inpcb *inp;
  321.         int errno;
  322. {
  323.  
  324.     inp->inp_socket->so_error = errno;
  325.     sorwakeup(inp->inp_socket);
  326.     sowwakeup(inp->inp_socket);
  327. }
  328.  
  329. void
  330. udp_ctlinput(cmd, sa, ip)
  331.     int cmd;
  332.     struct sockaddr *sa;
  333.     register struct ip *ip;
  334. {
  335.     register struct udphdr *uh;
  336.     extern struct in_addr zeroin_addr;
  337.     extern u_char inetctlerrmap[];
  338.  
  339.     if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
  340.         return;
  341.     if (ip) {
  342.         uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
  343.         in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
  344.             cmd, udp_notify);
  345.     } else
  346.         in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
  347. }
  348.  
  349. int
  350. udp_output(inp, m, addr, control)
  351.     register struct inpcb *inp;
  352.     register struct mbuf *m;
  353.     struct mbuf *addr, *control;
  354. {
  355.     register struct udpiphdr *ui;
  356.     register int len = m->m_pkthdr.len;
  357.     struct in_addr laddr;
  358.     int error = 0;
  359.     spl_t s;
  360.  
  361.     if (control)
  362.         m_freem(control);        /* XXX */
  363.  
  364.     if (addr) {
  365.         laddr = inp->inp_laddr;
  366.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  367.             error = EISCONN;
  368.             goto release;
  369.         }
  370.         /*
  371.          * Must block input while temporarily connected.
  372.          */
  373.         s = splnet();
  374.         error = in_pcbconnect(inp, addr);
  375.         if (error) {
  376.             splx(s);
  377.             goto release;
  378.         }
  379.     } else {
  380.         if (inp->inp_faddr.s_addr == INADDR_ANY) {
  381.             error = ENOTCONN;
  382.             goto release;
  383.         }
  384.     }
  385.     /*
  386.      * Calculate data length and get a mbuf
  387.      * for UDP and IP headers.
  388.      */
  389.     M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
  390.  
  391.     /*
  392.      * Fill in mbuf with extended UDP header
  393.      * and addresses and length put into network format.
  394.      */
  395.     ui = mtod(m, struct udpiphdr *);
  396.     ui->ui_next = ui->ui_prev = 0;
  397.     ui->ui_x1 = 0;
  398.     ui->ui_pr = IPPROTO_UDP;
  399.     ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
  400.     ui->ui_src = inp->inp_laddr;
  401.     ui->ui_dst = inp->inp_faddr;
  402.     ui->ui_sport = inp->inp_lport;
  403.     ui->ui_dport = inp->inp_fport;
  404.     ui->ui_ulen = ui->ui_len;
  405.  
  406.     /*
  407.      * Stuff checksum and output datagram.
  408.      */
  409.     ui->ui_sum = 0;
  410.     if (udpcksum) {
  411.         if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
  412.         ui->ui_sum = 0xffff;
  413.     }
  414.     ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
  415.     ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;    /* XXX */
  416.     ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;    /* XXX */
  417.     udpstat.udps_opackets++;
  418.     error = ip_output(m, inp->inp_options, &inp->inp_route,
  419.         inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
  420.  
  421.     if (addr) {
  422.         in_pcbdisconnect(inp);
  423.         inp->inp_laddr = laddr;
  424.         splx(s);
  425.     }
  426.     return (error);
  427.  
  428. release:
  429.     m_freem(m);
  430.     return (error);
  431. }
  432.  
  433. u_long    udp_sendspace = 9216;        /* really max datagram size */
  434. u_long    udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
  435.                     /* 40 1K datagrams */
  436.  
  437. int
  438. udp_usrreq(so, req, m, addr, control)
  439.     struct socket *so;
  440.     int req;
  441.     struct mbuf *m, *addr, *control;
  442. {
  443.     struct inpcb *inp = sotoinpcb(so);
  444.     int error = 0;
  445.     spl_t s;
  446.  
  447.     if (req == PRU_CONTROL)
  448.         return (in_control(so, (int)m, (caddr_t)addr,
  449.             (struct ifnet *)control));
  450.     if (inp == NULL && req != PRU_ATTACH) {
  451.         error = EINVAL;
  452.         goto release;
  453.     }
  454.     /*
  455.      * Note: need to block udp_input while changing
  456.      * the udp pcb queue and/or pcb addresses.
  457.      */
  458.     switch (req) {
  459.  
  460.     case PRU_ATTACH:
  461.         if (inp != NULL) {
  462.             error = EINVAL;
  463.             break;
  464.         }
  465.         s = splnet();
  466.         error = in_pcballoc(so, &udb);
  467.         splx(s);
  468.         if (error)
  469.             break;
  470.         error = soreserve(so, udp_sendspace, udp_recvspace);
  471.         if (error)
  472.             break;
  473.         ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
  474.         break;
  475.  
  476.     case PRU_DETACH:
  477.         udp_detach(inp);
  478.         break;
  479.  
  480.     case PRU_BIND:
  481.         s = splnet();
  482.         error = in_pcbbind(inp, addr);
  483.         splx(s);
  484.         break;
  485.  
  486.     case PRU_LISTEN:
  487.         error = EOPNOTSUPP;
  488.         break;
  489.  
  490.     case PRU_CONNECT:
  491.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  492.             error = EISCONN;
  493.             break;
  494.         }
  495.         s = splnet();
  496.         error = in_pcbconnect(inp, addr);
  497.         splx(s);
  498.         if (error == 0)
  499.             soisconnected(so);
  500.         break;
  501.  
  502.     case PRU_CONNECT2:
  503.         error = EOPNOTSUPP;
  504.         break;
  505.  
  506.     case PRU_ACCEPT:
  507.         error = EOPNOTSUPP;
  508.         break;
  509.  
  510.     case PRU_DISCONNECT:
  511.         if (inp->inp_faddr.s_addr == INADDR_ANY) {
  512.             error = ENOTCONN;
  513.             break;
  514.         }
  515.         s = splnet();
  516.         in_pcbdisconnect(inp);
  517.         inp->inp_laddr.s_addr = INADDR_ANY;
  518.         splx(s);
  519.         so->so_state &= ~SS_ISCONNECTED;        /* XXX */
  520.         break;
  521.  
  522.     case PRU_SHUTDOWN:
  523.         socantsendmore(so);
  524.         break;
  525.  
  526.     case PRU_SEND:
  527.         return (udp_output(inp, m, addr, control));
  528.  
  529.     case PRU_ABORT:
  530.         soisdisconnected(so);
  531.         udp_detach(inp);
  532.         break;
  533.  
  534.     case PRU_SOCKADDR:
  535.         in_setsockaddr(inp, addr);
  536.         break;
  537.  
  538.     case PRU_PEERADDR:
  539.         in_setpeeraddr(inp, addr);
  540.         break;
  541.  
  542.     case PRU_SENSE:
  543.         /*
  544.          * stat: don't bother with a blocksize.
  545.          */
  546. #ifndef AMITCP            /* stat not supported in AmiTCP */
  547.         return (0);
  548. #endif
  549.     case PRU_SENDOOB:
  550.     case PRU_FASTTIMO:
  551.     case PRU_SLOWTIMO:
  552.     case PRU_PROTORCV:
  553.     case PRU_PROTOSEND:
  554.         error =  EOPNOTSUPP;
  555.         break;
  556.  
  557.     case PRU_RCVD:
  558.     case PRU_RCVOOB:
  559.         return (EOPNOTSUPP);    /* do not free mbuf's */
  560.  
  561.     default:
  562.         panic("udp_usrreq");
  563.     }
  564.  
  565. release:
  566.     if (control) {
  567.         printf("udp control data unexpectedly retained\n");
  568.         m_freem(control);
  569.     }
  570.     if (m)
  571.         m_freem(m);
  572.     return (error);
  573. }
  574.  
  575. void
  576. udp_detach(inp)
  577.     struct inpcb *inp;
  578. {
  579.     spl_t s = splnet();
  580.  
  581.     if (inp == udp_last_inpcb)
  582.         udp_last_inpcb = &udb;
  583.     in_pcbdetach(inp);
  584.     splx(s);
  585. }
  586.